package com.gitee.wsl.doc.prosemirror.ui.inputrule

import com.gitee.wsl.doc.prosemirror.model.attr.Attrs
import com.gitee.wsl.doc.prosemirror.model.content.ext.findWrapping
import com.gitee.wsl.doc.prosemirror.model.node.Node
import com.gitee.wsl.doc.prosemirror.model.node.NodeType
import com.gitee.wsl.doc.prosemirror.model.node.ext.canJoin
import com.gitee.wsl.doc.prosemirror.state.EditorState
import com.gitee.wsl.doc.prosemirror.state.Transaction
import com.gitee.wsl.doc.prosemirror.transform.ext.delete
import com.gitee.wsl.doc.prosemirror.transform.ext.join
import com.gitee.wsl.doc.prosemirror.transform.ext.wrap

/**
 * ProseMirror风格输入规则包装器
 * 用于在编辑器中将匹配的内容包装为指定节点类型
 */
class InputRuleWrapperHandler<T : Node>(
    private val nodeType: NodeType,
    private val getAttrs: (() -> Attrs)? = null,
    private val joinPredicate: ((MatchResult, T) -> Boolean)? = null
) :InputRuleHandler{

    /**
     * 执行输入规则处理
     * @param state 编辑器状态
     * @param match 正则匹配结果
     * @param start 匹配开始位置
     * @param end 匹配结束位置
     * @return 处理事务，如果不适用则返回null
     */
    override fun execute(
        state: EditorState,
        match: MatchResult,
        start: Int,
        end: Int
    ): Transaction? {
        // 获取节点属性
        val attrs = getAttrs?.invoke()

        // 创建事务并删除匹配文本
        val tr = state.tr.delete(start, end)
        val startResolved = tr.doc.resolve(start)
        val range = startResolved.blockRange()
        val wrapping = range?.findWrapping( nodeType, attrs)

        // 检查是否可以包装
        if (wrapping == null) return null

        // 执行包装操作
        tr.wrap(range, wrapping)

        // 检查前一个节点是否可以合并
        val before = tr.doc.resolve(start - 1).nodeBefore
        if (before != null && before.type == nodeType &&
            tr.doc.canJoin( start - 1) && (joinPredicate == null || joinPredicate(match, before as T))) {
            tr.join(start - 1)
        }

        return tr
    }
}

/**
 * 创建输入规则包装器
 * @param regexp 匹配正则表达式
 * @param nodeType 目标节点类型
 * @param getAttrs 属性获取函数（可为null）
 * @param joinPredicate 节点合并条件函数（可为null）
 */
fun <T : Node> InputRule.Companion.wrapping(
    regexp: Regex,
    nodeType: NodeType,
    getAttrs: (() -> Attrs)? = null,
    joinPredicate: ((MatchResult, T) -> Boolean)? = null,
    options: InputRule.Options=InputRule.Options()
) = InputRuleWrapperHandler(nodeType,getAttrs,joinPredicate).toInputRule(regexp,options)